package com.zx.idc.backend.gui.ins;


import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.toolkit.IdWorker;
import com.rxliuli.rxeasyexcel.EasyExcel;
import com.rxliuli.rxeasyexcel.ResponseHelper;
import com.rxliuli.rxeasyexcel.domain.ExcelReadContext;
import com.rxliuli.rxeasyexcel.domain.ExcelWriteContext;
import com.rxliuli.rxeasyexcel.domain.ImportDomain;
import com.rxliuli.rxeasyexcel.read.ExcelReader;
import com.zx.idc.backend.gui.common.BaseApi;
import com.zx.idc.backend.gui.common.Result;
import com.zx.idc.backend.gui.common.base.BaseExcelApi;
import com.zx.idc.backend.gui.common.util.HttpServletUtil;
import com.zx.idc.backend.gui.ins.service.InsFilterInterfaceService;
import com.zx.idc.common.constants.ISMSPriorityConstant;
import com.zx.idc.common.exception.*;
import com.zx.idc.ds.common.constant.ReportStatusConstant;
import com.zx.idc.ds.ins.base.BaseFilterAndMonitorEntity;
import com.zx.idc.ds.ins.entity.InsFilter;
import com.zx.idc.ds.ins.service.IInsFilterService;
import com.zx.idc.ds.ins.vo.InsFilterVo;
import com.zx.idc.internal.exception.SendMessageException;
import com.zx.idc.qc.exception.JobExistsException;
import com.zx.idc.qc.exception.QuartzJobException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import static com.zx.idc.common.util.RandomUtils.getRandomChar;

/**
 * <p>
 * 过滤指令 前端控制器
 * </p>
 *
 * @author rxliuli
 * @since 2019-01-31
 */
@RestController
@RequestMapping("/api/insFilter")
public class InsFilterController extends BaseApi implements BaseExcelApi<IInsFilterService, InsFilterVo> {


    private static final int NUM = 10000;
    @Autowired
    private IInsFilterService iInsFilterService;

    @Autowired
    private InsFilterInterfaceService insFilterInterfaceService;

    @GetMapping("/query-page")
    @RequiresPermissions("regulatory-directive:ins-filter")
    public Result<Page<InsFilterVo>> queryPage(Page<InsFilterVo> page, InsFilterVo insFilterVo) {
        return success(iInsFilterService.queryPage(page, insFilterVo));
    }

    @PostMapping("/delete/batch")
    @RequiresPermissions("regulatory-directive:ins-filter:edit")
    public Result<Boolean> deleteAll(@RequestBody List<InsFilterVo> insFilterVos) {
        String errorMsg;
        Exception ex;
        try {
            for (InsFilterVo insFilterVo : insFilterVos) {
                insFilterInterfaceService.deleteInsFilter(insFilterVo);
            }
            return success(true);
        } catch (EncryptException e) {
            errorMsg = "删除过滤指令加密异常";
            ex = e;
        } catch (SendMessageException e) {
            errorMsg = "删除过滤指令发送指令异常";
            ex = e;
        } catch (QuartzJobException e) {
            errorMsg = "删除过滤指令发送指令异常";
            ex = e;
        } catch (CallInternalInterfaceException e) {
            errorMsg = "删除过滤指令调用内部接口失败";
            ex = e;
        }
        log.error(errorMsg, ex);
        return error(errorMsg);
    }

    @PostMapping("/add")
    @RequiresPermissions("regulatory-directive:ins-filter:edit")
    public Result<Boolean> add(@RequestBody InsFilterVo insFilterVo) {
        //设置优先级
        insFilterVo.setTimeStamp(LocalDateTime.now())
            .setLevel(ISMSPriorityConstant.INS_FILTER_BINARY_PRIORITY)
            .setOperationType(InsFilter.OPERATION_TYPE_ADD)
            .setInsSource(InsFilter.INS_SOURCE_ISMS)
            .setId(IdWorker.getIdStr());
        insFilterVo.setReportStatus(ReportStatusConstant.NOT_REPORTED);
        String errorMsg;
        Exception ex;
        try {
            return success(insFilterInterfaceService.add(insFilterVo));
        } catch (EncryptException e) {
            errorMsg = "添加过滤指令加密异常";
            ex = e;
        } catch (SendMessageException e) {
            errorMsg = "添加过滤指令发送指令异常";
            ex = e;
        } catch (QuartzJobException e) {
            errorMsg = "添加过滤指令发送指令异常";
            ex = e;
        } catch (JobExistsException e) {
            errorMsg = "添加过滤指令job异常";
            ex = e;
        } catch (CallInternalInterfaceException e) {
            errorMsg = "添加过滤指令调用内部接口失败";
            ex = e;
        } catch (GlobalException e) {
            errorMsg = e.getMessage();
            ex = e;
        }
        log.error(errorMsg, ex);
        return error(errorMsg);
    }

    @PostMapping("/update")
    @RequiresPermissions("regulatory-directive:ins-filter:edit")
    public Result<Boolean> update(@RequestBody InsFilterVo insFilterVo) {
        insFilterVo.setLevel(ISMSPriorityConstant.INS_FILTER_BINARY_PRIORITY);
        String errorMsg;
        Exception ex;
        try {
            return success(insFilterInterfaceService.updateInsFilter(insFilterVo));
        } catch (EncryptException e) {
            errorMsg = "更新过滤指令调用内部接口失败";
            ex = e;
        } catch (SendMessageException e) {
            errorMsg = "更新过滤指令调用内部接口失败";
            ex = e;
        } catch (QuartzJobException e) {
            errorMsg = "更新过滤指令调用内部接口失败";
            ex = e;
        } catch (JobExistsException e) {
            errorMsg = "更新过滤指令调用内部接口失败";
            ex = e;
        } catch (CallInternalInterfaceException e) {
            errorMsg = "更新过滤指令调用内部接口失败";
            ex = e;
        } catch (InstructionUpdateTimeOutException e) {
            errorMsg = e.getMessage();
            ex = e;
        } catch (GlobalException e) {
            errorMsg = e.getMessage();
            ex = e;
        }
        log.error("更新过滤指令调用内部接口失败", ex);
        return error(errorMsg);
    }

    /**
     * 获取一个 Service，由子类实现
     * 实现这个方法可以更快的获取到 Service 以提高响应速度
     *
     * @return 服务类实现对象
     */
    @Override
    public Optional<IInsFilterService> getService() {
        return Optional.of(iInsFilterService);
    }

    /**
     * 导出 Excel 模板
     */
    @Override
    public void downloadTemplate() {

        final OutputStream outputStream = ResponseHelper.wrapper(HttpServletUtil.getResponse(), "导出 Excel.xlsx");
        EasyExcel.export(outputStream)
            .export(ExcelWriteContext.builder(true)
                .headers(InsFilterVo.class)
                .datasource(Collections.emptyList())
                .build()
            )
            .write();
    }

    private List<BaseFilterAndMonitorEntity> getDownloadTemplateData() {
        ArrayList<BaseFilterAndMonitorEntity> filterVos = new ArrayList<>();
        LocalDateTime effectTime = LocalDateTime.now();
        LocalDateTime expiredTime = effectTime.plusDays(1);
        for (int i = 1; i <= 10000; i++) {
            String valueStart = getRandomChar() + getRandomChar();
            filterVos.add(
                new InsFilterVo()
                    .setReason("测试关键字" + i)
                    .setLog(InsFilter.LOG_YES)
                    .setReport(InsFilter.REPORT_YES)
                    .setEffectTime(effectTime)
                    .setExpiredTime(expiredTime)
                    .setIdcId("10011")
                    .setHouseId("1")
                    .setSubtype("3")
                    .setValueStart(valueStart)
                    .setKeywordRange("0,1,2")
            );
        }

        return filterVos;
    }

    private List<BaseFilterAndMonitorEntity> getIpAndPortDownloadTemplateData() {
        ArrayList<BaseFilterAndMonitorEntity> insFilters = new ArrayList<>(NUM);
        LocalDateTime effectTime = LocalDateTime.now();
        LocalDateTime expiredTime = effectTime.plusDays(1);
        int three = 100;
        int a = 1;
        int two = 100;
        int one = 183;
        for (int i = 1; i <= NUM; i++) {
            if (i % 255 == 0) {
                ++three;
                a = 1;
                if (three % 255 == 0) {
                    three = 1;
                    ++two;
                    if (two % 255 == 0) {
                        ++one;
                        two = 1;
                        if (one % 255 == 0) {
                            break;
                        }
                    }
                }
            }
            String startValue = one + "." + two + "." + three + "." + (a++) + "|" + i;
            if (i == 2000) {
                startValue = "183.236.27.2|8083";
            } else if (i == 4000) {
                startValue = "183.236.27.2|8082";
            } else if (i == 6000) {
                startValue = "183.236.27.2|8081";
            } else if (i == 10000) {
                startValue = "183.236.27.2|19787";
            }
            insFilters.add(
                new InsFilterVo()
                    .setReason("测试目的端口" + i)
                    .setLog(InsFilter.LOG_YES)
                    .setReport(InsFilter.REPORT_YES)
                    .setEffectTime(effectTime)
                    .setExpiredTime(expiredTime)
                    .setIdcId("10011")
                    .setHouseId("1")
                    .setSubtype("5|7")
                    .setValueStart(startValue)
            );
        }
        return insFilters;
    }

    /**
     * 导入 Excel
     *
     * @param file 上传的 Excel 文件
     */
    @Override
    public void importData(MultipartFile file) {
        try {
            byte[] byteArr = file.getBytes();
            try (
                final InputStream inputStream = new ByteArrayInputStream(byteArr);
                final ExcelReader excelReader = EasyExcel.read(inputStream)
            ) {
                final ImportDomain<InsFilterVo> importDomain = excelReader.resolve(
                    ExcelReadContext.<InsFilterVo>builder()
                        .clazz(InsFilterVo.class)
                        .build()
                );
                if (CollectionUtils.isNotEmpty(importDomain.getErrors())) {
                    final OutputStream outputStream = ResponseHelper.wrapper(HttpServletUtil.getResponse(), "导出 Excel.xlsx");
                    EasyExcel.export(outputStream)
                        .export(ExcelWriteContext.builder(true)
                            .datasource(importDomain.getData())
                            .errors(importDomain.getErrors())
                            .build()
                        )
                        .write();
                    return;
                }
                List<InsFilterVo> data = importDomain.getData();
                if (data == null || data.isEmpty()) {
                    return;
                }
                ImportDomain<InsFilterVo> domain;
                try {
                    domain = insFilterInterfaceService.importData(data, importDomain.getColumnInfoMap());
                } catch (ExcelImportErrorException e) {
                    domain = (ImportDomain) e.getData();
                }

                if (domain == null) {
                    return;
                }
                if (CollectionUtils.isNotEmpty(domain.getErrors())) {
                    final OutputStream outputStream = ResponseHelper.wrapper(HttpServletUtil.getResponse(), "导出 Excel.xlsx");
                    EasyExcel.export(outputStream)
                        .export(ExcelWriteContext.builder(true)
                            .datasource(domain.getData())
                            .errors(domain.getErrors())
                            .build()
                        )
                        .write();
                }
            }
        } catch (IOException | EncryptException | JobExistsException | QuartzJobException | SendMessageException e) {
            _log.error("导入异常", e);
        }
    }
}

